
//  类型判断 promise return 符合 true 不符合 false
const isPromise = val => {
  return isObject(val) && isFunction(val.then) && isFunction(val.catch)
}
//  类型判断 object
const isObject = val => {
  return val !== null && typeof val === "object"
}
//  类型判断 function
const isFunction = val => {
  return typeof val === "function"
}

//  类型判断 string
const isString = val => {
  return typeof val === "string"
}

// 执行类型判断 string
const runString = (val, tip, key) => {
  if (isString(val)) return !isString(val)
  console.error(`${key}${tip}`)
  return isString(val)
}


// 获取对象方法
function getObjFunc(path, obj) {
  if (!path) return console.error('预加载方法参数不可为空')
  if (runString(path, '预加载方法参数格式错误', 'pathArr')) return
  let pathArr = path.split('.');
  if (pathArr instanceof Array && pathArr.length > 0) {
    pathArr.forEach(key => {
      obj = obj[key]
    })
    if (isFunction(obj)) {
      return obj
    } else {
      console.error('预加载方法不存在或者参数有误')
    }
  } else {
    console.error('预加载方法参数格式错误')
  }
}

// uniApp 缓存方式 
import cache from './cache'


const _httpObj = Symbol("httpObj")
const _promiseResult = Symbol("httpObj")
const _httpFunc = Symbol("httpFunc")
class Preload {
  // 构造器
  constructor(httpFunc, Debug = false) {
    if (!isObject(httpFunc)) return console.error("缺少预加载请求方法")
    if (!cache) return console.error("缓存方法错误")
    this[_httpFunc] = httpFunc // 注册全局请求方法
    this[_promiseResult] = {} // 注册全局promise响应对象
    this[_httpObj] = cache.get("preload") || {} // 注册全局请求参数缓存对象
  }

  // 新增预加载方法
  addHttp(id, funcPath, params = {}) {
    if (runString(id, "参数必须为字符串类型", "id")) return this
    if (runString(funcPath, '参数不可为空', 'funcPath')) return this
    if (this[_promiseResult][id]) return // 存在预加载结果，不再新增
    this[_httpObj][id] = {
      funcPath,
      params,
    }
    cache.set("preload", this[_httpObj])
    this[_promiseResult][id] = null
    return this
  }

  // 新增 并 立即执行预加载方法
  runAddHttp(id, funcPath, params = {}) {
    if (runString(id, "参数必须为字符串类型", "id")) return this
    if (runString(funcPath, '参数不可为空', 'funcPath')) return this
    if (this[_promiseResult][id]) return // 存在预加载结果，不再新增
    this[_httpObj][id] = {
      funcPath,
      params,
    }
    cache.set("preload", this[_httpObj])
    this[_promiseResult][id] = null
    this.send(id)
    return this
  }

  // 删除预加载方法
  removeHttp(id) {
    if (runString(id, "参数必须为字符串类型", "id")) return this
    if (!isObject(this[_httpObj][id])) {
      console.error("无效预加载id，请检查是否已经添加过预加载函数")
      return this
    }
    delete this[_httpObj][id] // 删除预加载参数
    delete this[_promiseResult][id] // 删除预加载结果
    cache.set("preload", this[_httpObj])
    return this
  }

  // 获取请求结果
  getData(id) {
    if (runString(id, "参数必须为字符串类型", "id")) return
    if (!isObject(this[_httpObj][id])) {
      return Promise.reject("无效预加载id,数据获取失败")
    }
    if (isPromise(this[_promiseResult][id])) {
      return this[_promiseResult][id]
    } else {
      this.send(id)
      return this[_promiseResult][id]
    }

  }

  // 发送请求
  send(id) {
    if (runString(id, "参数必须为字符串类型", "id")) return this
    if (!isObject(this[_httpObj][id])) {
      console.error("无效预加载id，请检查是否已经添加过预加载函数")
      return this
    }
    this[_promiseResult][id] = new Promise((resolve, reject) => {
      let func = getObjFunc(this[_httpObj][id].funcPath, this[_httpFunc])(this[_httpObj][id].param) // 开始执行请求
      if (isPromise(func)) {
        func
          .then(res => {
            resolve(res)
          })
          .catch(err => {
            reject(err)
          })
      } else {
        reject("预加载函数必须为Promise")
      }
    })

    return this
  }
}

export default Preload
